#ifndef __BYTE_AREA__
#define __BYTE_AREA__

namespace xm
{
	template < typename T >
	struct br
	{
		typedef const T *	elmtptr_t;
	
		struct byte_rgn_t
		{
			elmtptr_t	_current;
			elmtptr_t	_last;

			inline byte_rgn_t() : _current(0), _last(0)
			{}

			inline byte_rgn_t( const void * elmtp, const void * lastp )
				: _current( (elmtptr_t)elmtp )
				, _last( (elmtptr_t)lastp )
			{}
			inline byte_rgn_t( const void * elmtp, size_t ssCount )
				: _current( (elmtptr_t)elmtp )
				, _last( (elmtptr_t)elmtp + ssCount )
			{}

			inline elmtptr_t cur_ptr(){ return _current; };

			inline bool_t set_buffer( const void * datp, size_t cbBytes )
			{
				_current = (elmtptr_t)datp;
				_last = _current + cbBytes;
				return _current <= _last;
			}

			inline bool_t set_last( const void * datp )
			{
				if( datp < _current ) return FALSE;
				_last = (elmtptr_t)datp;
				return TRUE;
			}

			template < class P > 
			inline bool_t fetchp( P * & outp, size_t tcnt )
			{
				elmtptr_t destp = seek_test( sizeof(P) * tcnt );
				if( !destp ) return FALSE;
				outp = (P*)_current;
				_current = destp;
				return TRUE;
			}
			template < class P > 
			inline bool_t peekp( P * & outp, size_t tcnt )
			{
				elmtptr_t destp = seek_test( sizeof(P) * tcnt );
				if( !destp ) return FALSE;
				outp = (P*)_current;
				return TRUE;
			}
			template < class V > 
			inline bool_t fetchv( V & valref )
			{
				elmtptr_t destp = seek_test(sizeof(valref));
				if( !destp ) return FALSE;
				valref = *(V*)_current;
				_current = destp;
				return TRUE;
			}
			template < class V > 
			inline bool_t peekv( V & valref )
			{
				elmtptr_t destp = seek_test(sizeof(valref));
				if( !destp ) return FALSE;
				valref = *(V*)_current;
				return TRUE;
			}
			inline bool_t fetch_byte_region( byte_rgn_t & region, size_t want )
			{
				elmtptr_t destp = seek_test( want );
				if( !destp ) return FALSE;
				region._current = _current;
				region._last = destp;
				_current = destp;
				return TRUE;
			}
			inline bool_t peek_byte_region( byte_rgn_t & region, size_t want )
			{
				elmtptr_t destp = seek_test( want );
				if( !destp ) return FALSE;
				region._current = _current;
				region._last = destp;
				return TRUE;
			}
			inline elmtptr_t seek_test( ssize_t idist )
			{
				elmtptr_t destp = _current + idist;
				if( destp > _last || destp < _current )
					return NULL;
				return destp;
			}
			inline elmtptr_t seekp( ssize_t idist )
			{
				elmtptr_t destp = seek_test( idist );
				if( !destp ) return FALSE;
				elmtptr_t retp = _current;
				_current = destp;
				return retp;
			}

			inline size_t rest_bytes()
			{
				return _last - _current;
			}

			inline size_t bytes()
			{
				return _last - _current;
			}

			inline bool_t set_current( elmtptr_t currp )
			{
				if( currp > _last ) return FALSE;
				_current = currp;
				return TRUE;
			}

			template < class V > 
			inline bool_t fetchlebu32( V & valref )
			{
				size_t max_loop = rest_bytes();
				max_loop = max_loop < 5 ? max_loop : 5;
				elmtptr_t bpend = _current + max_loop;
				uint32_t tmp = 0;
				uint8_t shift = 0;
				for( ; _current < bpend; )
				{
					uint8_t bh = *_current ++ ;
					tmp |= ( ( (uint32_t)bh & 0x7F ) << shift );
					if( !(bh & 0x80) ) break;
					shift += 7;
				}
				valref = tmp;
				return true;
			}
			template < class V > 
			inline bool_t fetchlebs32( V & valref )
			{
				size_t max_loop = rest_bytes();
				max_loop = max_loop < 5 ? max_loop : 5;
				elmtptr_t bpend = _current + max_loop;
				int32_t tmp = 0;
				uint8_t shift = 0;
				for( ; _current < bpend; )
				{
					int8_t ch = *_current ++ ;
					tmp |= ( ( ((int32_t)ch) & 0x7F ) << shift );
					shift += 7;
					if( !(ch & 0x80) ) break;
				}
				if( shift < 32 )
					tmp = tmp << (32-shift) >> (32-shift);
				valref = tmp;
				return true;
			}

		};
	
		struct byte_rgnl_t : byte_rgn_t
		{
			using byte_rgn_t::_current;
			using byte_rgn_t::_last;
		
			elmtptr_t	_first;

			inline byte_rgnl_t() : byte_rgn_t(), _first(0)
			{}

			inline byte_rgnl_t( const void* elmtp, const void* lastp )
				: byte_rgn_t(elmtp, lastp)
				, _first( (elmtptr_t)elmtp )
			{}
			inline byte_rgnl_t( const void* elmtp, size_t ssCount )
				: byte_rgn_t(elmtp, ssCount)
				, _first( (elmtptr_t)elmtp )
			{}
			inline byte_rgnl_t( const void* emltp, const void* lastp, const void * currp )
				: byte_rgn_t(currp, lastp)
				, _first( (elmtptr_t)emltp )
			{}

			inline VOID reset()
			{
				_current = _first;
			}

			inline size_t offset()
			{
				return _current - _first;
			}

			inline bool_t set_current( elmtptr_t currp )
			{
				if( currp < _first || currp > _last ) 
					return FALSE;
				_current = currp;
				return TRUE;
			}

			inline bool_t set_offset( size_t ioffset )
			{
				return set_current( _first + ioffset );
			}

			inline elmtptr_t seek_test( ssize_t idist )
			{
				elmtptr_t destp = _current + idist;
				if( destp > _last || destp < _first )
					return NULL;
				return destp;
			}
			inline elmtptr_t seekp( ssize_t idist )
			{
				elmtptr_t destp = seek_test( idist );
				if( !destp ) return FALSE;
				elmtptr_t retp = _current;
				_current = destp;
				return retp;
			}
			inline size_t bytes()
			{
				return _last - _first;
			}
		};
	};

	typedef br<uint8_t>::byte_rgn_t		byte_region_t;
	typedef br<uint8_t>::byte_rgnl_t	byte_region_ex_t;

};

#endif